package com.vdong.trade.order.service.dubbo;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.vdong.interactive.course.facade.PeddleGoodsFacadeService;
import com.vdong.trade.order.common.contract.OrderStateMachineEventModelContract;
import com.vdong.trade.order.common.contract.TableContract;
import com.vdong.trade.order.common.enums.TypeEnum;
import com.vdong.trade.order.common.exception.ProcessException;
import com.vdong.trade.order.entity.dto.param.*;
import com.vdong.trade.order.entity.dto.result.*;
import com.vdong.trade.order.entity.mo.*;
import com.vdong.trade.order.facade.OrderFacade;
import com.vdong.trade.order.repository.OrderDisbSnapshotMORepository;
import com.vdong.trade.order.repository.OrderMORepository;
import com.vdong.trade.order.repository.SellHotMORepository;
import com.vdong.trade.trading.facade.AmountFacade;
import com.vdong.trade.trading.facade.TradingFacade;
import com.vdong.trade.trading.facade.enums.UserTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.lamb.framework.common.remote.FacadeResult;
import org.lamb.framework.common.util.*;
import org.lamb.framework.core.annotation.LambValid;
import org.lamb.framework.statemachine.handler.LambStateMachine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.math.BigDecimal;
import java.util.*;

import static com.vdong.trade.order.common.enums.ProcessExceptionEnum.*;

/**
 * @author zhoulongbiao
 * @Date 2018/12/14 17:28
 */
@Service
@Slf4j
@com.alibaba.dubbo.config.annotation.Service
public class OrderFacadeImpl implements OrderFacade {

    @Resource
    private LambStateMachine lambStateMachine;

    @Resource
    private OrderMORepository orderMORepository;

    @Resource
    private SellHotMORepository sellHotMORepository;

    @Reference
    private TradingFacade tradingFacade;

    @Reference
    private AmountFacade amountFacade;

    @Reference
    private PeddleGoodsFacadeService peddleGoodsFacadeService;

    @Autowired
    private OrderDisbSnapshotMORepository orderDisbSnapshotMORepository;

    @Override
    @LambValid
    public String execute(String paramDTO) throws Exception {
        log.info("execute,入参为:[{}]", JSON.toJSONString(paramDTO));
        OrderStateMachineParamDTO param = JSON.parseObject(paramDTO, OrderStateMachineParamDTO.class);
        Object result = lambStateMachine.<String>execute(() -> {
            if (param.getEvent().startsWith(OrderStateMachineEventModelContract.DISB_ORDER_EVENT_MODEL))
                return Optional.ofNullable(orderMORepository.selectOrderByEntity(OrderMO.builder()
                        .orderNo(param.getOrderNo())
                        .status(TableContract.Order.status.EFFECTIVE).build()))
                        .orElseThrow(() -> new ProcessException(EB00000000)).getOrderStatus();
            throw new ProcessException(EB00000100);
        }, param.getEvent(), param.getData());
        return FacadeResultUtils.succFacadeBeanToString(OrderStateMachineResultDTO.builder().
                alternativeData(result).event(param.getEvent()).build());
    }

    @Override
    public String selectOrderMessageByOrderNo(String paramDTO) {
        log.info("selectOrderMessageByOrderNo,入参为:[{}]", JSON.toJSONString(paramDTO));
        CountOrderParamDTO dto = JSON.parseObject(paramDTO, CountOrderParamDTO.class);
        OrderMO orderMO = orderMORepository.selectOrderByEntity(OrderMO.builder().orderNo(dto.getOrderNo()).build());
        if (StringUtil.hasBlank(orderMO)) return FacadeResultUtils.failFacadeBeanToString("未找到对象！");
        return FacadeResultUtils.succFacadeBeanToString(orderMO);
    }

    @Override
    public String settlementOrderTask() {
        log.info("每日结算task=================>start");
        //0点2分 查询前日已付款订单
        List<OrderMO> orderMOList = orderMORepository.settlementOrderTask();
        List<TradingParamMO> list = new ArrayList<>();
        //更新订单状态
        for (OrderMO mo : orderMOList) {
            mo.setOrderStatus(TableContract.Order.OrderStatus.DisbOrderStatus.SETTLEMENT);
            int row = orderMORepository.updateOrderById(mo);
            if (row < 1) log.info("更新结算订单失败,orderId为:[{}]", mo.getId());

            TradingParamMO tradingParamMO = orderMORepository.selectTradingParam(mo.getOrderNo());
            if (StringUtil.hasBlank(tradingParamMO)) throw new ProcessException(EB00000011);
            list.add(tradingParamMO);
        }

        //更新交易流水结算状态
        FacadeResult<FacadeResult> tradeResult = FacadeResultUtils.stringToFacadeBean
                (tradingFacade.saveOrUpdateTrading(JSON.toJSONString(orderMOList)), FacadeResult.class);
        if (!tradeResult.isSuccess()) throw new ProcessException(EB00000004);

        //更新推客和商户金额 减少未结算 增加可提现
        FacadeResult<FacadeResult> amountResult = FacadeResultUtils.stringToFacadeBean
                (amountFacade.updatePusherAndMerchantAmount(JSON.toJSONString(list)), FacadeResult.class);
        if (!amountResult.isSuccess()) throw new ProcessException(EB00000004);
        log.info("结算定时任务结束===================");
        return FacadeResultUtils.succFacadeBeanToString(FacadeResult.buildSucc());
    }

    @Override
    public String orderTransaction(String param) {
        log.info("orderTransaction,入参为:[{}]", JSON.toJSONString(param));
        CountOrderParamDTO dto = JSON.parseObject(param, CountOrderParamDTO.class);
        OrderTransactionMO orderTransactionMO = null;
        if (dto.getUserType().compareTo(UserTypeEnum.COMPANY.getValue().toString()) == 0) {
            orderTransactionMO = orderMORepository.selectOrderTransactionByParam
                    (CountOrderSettlementParamDTO.builder().date(dto.getDate()).companyKey(dto.getUserId()).build());
            if (StringUtil.hasBlank(orderTransactionMO)) throw new ProcessException(EB00000012);
        } else if (dto.getUserType().compareTo(UserTypeEnum.MERCHANT.getValue().toString()) == 0) {
            log.info("orderTransaction merchant==================================");
            orderTransactionMO = orderMORepository.selectOrderTransactionByParam
                    (CountOrderSettlementParamDTO.builder().date(dto.getDate()).merchantKey(dto.getUserId()).build());
            if (StringUtil.hasBlank(orderTransactionMO)) throw new ProcessException(EB00000012);
        } else if (dto.getUserType().compareTo(UserTypeEnum.PUSHER.getValue().toString()) == 0) {
            log.info("orderTransaction PUSHER==================================[{}]");
            orderTransactionMO = orderMORepository.selectOrderTransactionByParam
                    (CountOrderSettlementParamDTO.builder().date(dto.getDate()).pusherKey(dto.getUserId()).build());
            if (StringUtil.hasBlank(orderTransactionMO)) throw new ProcessException(EB00000012);
        }
        return FacadeResultUtils.succFacadeBeanToString
                (CopyUtil.copyObject(orderTransactionMO, new OrderTransactionResultDTO()));
    }

    @Override
    public String sellHotWeek() {
        log.info("周榜sellHotWeek task=================>start");
        try {
            SellHotParamDTO sellHotParamDTO = new SellHotParamDTO();
            sellHotParamDTO.setStartTime(DateUtil.getThisWeekMonday(new Date()));
            sellHotParamDTO.setEndTime(DateUtil.getThisWeekSunday(new Date()));
            List<SellHotWeekMO> sellHotWeekMOs = orderMORepository.sellHot(sellHotParamDTO);
            if (sellHotWeekMOs.size() < 1) throw new ProcessException(EB00000012);
            List<SellHotMO> list = new ArrayList<>();
            for (SellHotWeekMO mo : sellHotWeekMOs) {
                String basePeddleGoodsDetail = peddleGoodsFacadeService.getBasePeddleGoodsDetail
                        (JSON.toJSONString(PeddleUserParamDTO.builder().peddleGoodsId(Long.valueOf(mo.getProductKey())).build()));
                if (StringUtil.hasBlank(basePeddleGoodsDetail)) throw new ProcessException(EB00000003);
                BasePeddleGoodsDTO disbProduct = FacadeResultUtils.stringToFacadeBean(basePeddleGoodsDetail,
                        BasePeddleGoodsDTO.class).getData();
                SellHotMO build = SellHotMO.builder().sellNum(Integer.valueOf(mo.getNum())).type(TypeEnum.WEEK.getValue())
                        .productKey(Long.valueOf(mo.getProductKey())).goodsName(disbProduct.getGoodsName())
                        .imagUrl(disbProduct.getImageUrl()).price(disbProduct.getPrice())
                        .pusherCommissionRate(new BigDecimal(mo.getPusherCommissionRate()))
                        .pusherAnticipatedIncomeAmount(new BigDecimal(mo.getPusherAnticipatedIncomeAmount()))
                        .createTime(new Date()).updateTime(new Date()).subType(String.valueOf(disbProduct.getSubType())).build();
                sellHotMORepository.insert(build);
            }
            log.info("周榜sellHotWeek task=================>end");
        } catch (Exception e) {
            log.error("周榜sellHotWeek 异常:", e);
            throw new RuntimeException("周榜sellHotWeek异常");
        }
        return FacadeResult.buildSucc().toString();
    }

    @Override
    public String sellHotMonth() {
        log.info("月榜sellHotMonth task=================>start");
        try {
            SellHotParamDTO sellHotParamDTO = new SellHotParamDTO();
            sellHotParamDTO.setStartTime(DateUtil.getFirstDayByMonth(DateUtil.getYearAndMonth()));
            sellHotParamDTO.setEndTime(DateUtil.getLastDayByMonth(DateUtil.getYearAndMonth()));
            List<SellHotWeekMO> sellHotWeekMOs = orderMORepository.sellHot(sellHotParamDTO);
            if (sellHotWeekMOs.size() < 1) throw new ProcessException(EB00000012);
            for (SellHotWeekMO mo : sellHotWeekMOs) {
                String basePeddleGoodsDetail = peddleGoodsFacadeService.getBasePeddleGoodsDetail
                        (JSON.toJSONString(PeddleUserParamDTO.builder().peddleGoodsId(Long.valueOf(mo.getProductKey())).build()));
                if (StringUtil.hasBlank(basePeddleGoodsDetail)) throw new ProcessException(EB00000003);
                BasePeddleGoodsDTO disbProduct = FacadeResultUtils.stringToFacadeBean(basePeddleGoodsDetail,
                        BasePeddleGoodsDTO.class).getData();
                SellHotMO build = SellHotMO.builder().sellNum(Integer.valueOf(mo.getNum())).type(TypeEnum.MONTH.getValue())
                        .productKey(Long.valueOf(mo.getProductKey())).goodsName(disbProduct.getGoodsName())
                        .imagUrl(disbProduct.getImageUrl()).price(disbProduct.getPrice())
                        .pusherCommissionRate(new BigDecimal(mo.getPusherCommissionRate()))
                        .pusherAnticipatedIncomeAmount(new BigDecimal(mo.getPusherAnticipatedIncomeAmount()))
                        .createTime(new Date()).updateTime(new Date()).subType(String.valueOf(disbProduct.getSubType())).build();
                sellHotMORepository.insert(build);
            }
            log.info("月榜sellHotMonth task=================>end");
        } catch (Exception e) {
            log.error("月榜sellHotMonth 异常:", e);
            throw new RuntimeException("月榜sellHotMonth异常");
        }
        return FacadeResult.buildSucc().toString();
    }

    @Override
    public String todayAndAllSell(String param) {
        log.info("todayAndAllSell,入参为:[{}]", JSON.toJSONString(param));
        CountOrderParamDTO dto = JSON.parseObject(param, CountOrderParamDTO.class);
        TodayAndAllSellMO todayAndAllSellMo = orderMORepository.selectTodayAndAllSell(dto);
        return FacadeResultUtils.succFacadeBeanToString(todayAndAllSellMo);
    }

    @Override
    public String pusherTodayAndAllSell(String param) {
        log.info("pusherTodayAndAllSell,入参为:[{}]", JSON.toJSONString(param));
        try {
            TodayAndAllSellMO todayAndAllSellMo = new TodayAndAllSellMO();
            CountOrderParamDTO dto = JSON.parseObject(param, CountOrderParamDTO.class);
            TodayAndAllSellMO todayAndAllSellMo2 = orderMORepository.selectPusherTodayAndAllSell(dto);

            if (StringUtil.hasBlank(todayAndAllSellMo2)) {
                todayAndAllSellMo.setAllSell("0");
                todayAndAllSellMo.setTodaySell("0");
            } else {
                todayAndAllSellMo = todayAndAllSellMo2;
            }
            return FacadeResultUtils.succFacadeBeanToString(todayAndAllSellMo);
        } catch (Exception e) {
            log.error("pusherTodayAndAllSell接口异常:", e);
            return FacadeResultUtils.failFacadeBeanToString(e.getMessage());
        }
    }

    @Override
    public String autoCanelOrder() {
        //查询当前时间16分钟之前待支付的订单
        List<OrderMO> orderMOList = orderMORepository.autoCanelOrder();
        if (StringUtil.hasBlank(orderMOList) || orderMOList.size() < 1) {
            return FacadeResult.buildSucc().toString();
        }
        for (OrderMO mo : orderMOList) {
            mo.setOrderStatus(TableContract.Order.OrderStatus.DisbOrderStatus.CANCEL);
            int row = orderMORepository.updateOrderById(mo);
            if (row < 1) log.info("更新取消订单失败,orderId为:[{}]", mo.getId());
        }
        return FacadeResult.buildSucc().toString();
    }

    @Override
    public String sumOrderMoney(String param) {
        log.info("sumOrderMoney,入参为:[{}]", JSON.toJSONString(param));
        try {
            CountOrderParamDTO dto = JSON.parseObject(param, CountOrderParamDTO.class);
            TodayAndAllSellMO todayAndAllSellMO = null;
            if (UserTypeEnum.PUSHER.getValue().toString().equals(dto.getUserType())) {
                todayAndAllSellMO = orderMORepository.sumOrderMoney
                        (CountOrderSettlementParamDTO.builder().pusherKey(dto.getUserId()).build());
            } else if (UserTypeEnum.MERCHANT.getValue().toString().equals(dto.getUserType())) {
                todayAndAllSellMO = orderMORepository.sumOrderMoney
                        (CountOrderSettlementParamDTO.builder().merchantKey(dto.getUserId()).build());
            }
            if (StringUtil.hasBlank(todayAndAllSellMO)) {
                log.info("todayAndAllSellMO为空，返回0");
                return FacadeResultUtils.succFacadeBeanToString(TodayAndAllSellMO
                        .builder().allSell("0").sumOrderMoney("0").todaySell("0").build());
            }
            log.info("sumOrderMoney返回的参数是：[{}]", JSON.toJSONString(todayAndAllSellMO));
            return FacadeResultUtils.succFacadeBeanToString(todayAndAllSellMO);
        } catch (Exception e) {
            log.error("sumOrderMoney接口异常:", e);
            return JSON.toJSONString(FacadeResult.buildFail("接口异常!"));
        }
    }

    @Override
    public String getSalesAndEarningsByGoods(String request) {
        try {
            log.info("getSalesAndEarningsByGoods接口入参:[{}]", request);
            if (StringUtil.hasBlank(request)) {
                return JSON.toJSONString(FacadeResult.buildFail("入参不能为空!"));
            }
            SalesAndEarningsByGoodsParamDTO goodsParamDTO = JSON.parseObject(request, SalesAndEarningsByGoodsParamDTO.class);

            SalesAndEarningsByGoodsResultDTO resultDTO = new SalesAndEarningsByGoodsResultDTO();
            //根据商品信息查询商品销量
            OrderParamMO orderParamMO = new OrderParamMO();
            orderParamMO.setProductKey(goodsParamDTO.getProductId());
            List<Long> idList = orderMORepository.selectOrderIdListByParam(orderParamMO);

            resultDTO.setTotalSales((long) idList.size());
            if (CollectionUtils.isEmpty(idList)) {
                resultDTO.setTotalProfit(BigDecimal.ZERO);
                resultDTO.setTodaySales(0L);
                return JSON.toJSONString(FacadeResult.buildSucc(JSON.toJSONString(resultDTO)));
            }

            //查询总收益
            BigDecimal amount = orderDisbSnapshotMORepository.selectTotalAmountByOrderIds(idList);
            resultDTO.setTotalProfit(amount);

            //获取当日销量
            orderParamMO.setStartTime(getStartTimeByday(0));
            orderParamMO.setEndTime(getStartTimeByday(1));
            List<Long> idList2 = orderMORepository.selectOrderIdListByParam(orderParamMO);

            resultDTO.setTodaySales((long) idList2.size());
            return JSON.toJSONString(FacadeResult.buildSucc(JSON.toJSONString(resultDTO)));
        } catch (Exception e) {
            log.error("getSalesAndEarningsByGoods接口异常:", e);
            return JSON.toJSONString(FacadeResult.buildFail("接口异常!"));
        }
    }

    @Override
    public String merchantOrderMoney(String param) {
        log.info("merchantOrderMoney接口入参:[{}]", param);
        try {
            CountOrderParamDTO dto = JSON.parseObject(param, CountOrderParamDTO.class);
            TodayAndAllSellMO todayAndAllSellMO = orderMORepository.merchantOrderMoney(dto);
            if (StringUtil.hasBlank(todayAndAllSellMO)) {
                return FacadeResultUtils.succFacadeBeanToString(TodayAndAllSellMO.builder().sumOrderMoney("0").build());
            }
            return FacadeResultUtils.succFacadeBeanToString(todayAndAllSellMO);
        } catch (Exception e) {
            log.error("merchantOrderMoney接口异常:", e);
            return JSON.toJSONString(FacadeResult.buildFail("接口异常!"));
        }

    }

    /**
     * 得到当天的开始时间
     *
     * @param day 当天往后推迟的天数
     * @return
     */
    private static Date getStartTimeByday(int day) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        cal.add(Calendar.DAY_OF_MONTH, day);
        return cal.getTime();
    }

    public static void main(String[] args) {
        System.out.println(DateUtil.getTimeToStr(getStartTimeByday(0)));
        System.out.println(DateUtil.getTimeToStr(getStartTimeByday(1)));

        Long count = 0L;
        System.out.println(count == 0);
    }
}
